package com.jffccloud.common.redis;

import com.jffccloud.common.util.SerializerUtil;
import com.jfinal.plugin.redis.IKeyNamingPolicy;
import redis.clients.jedis.JedisCluster;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class JedisClientCluster implements IJedisClient{

    private JedisCluster jedisPool;

    private IKeyNamingPolicy keyNamingPolicy;

    private SerializerUtil serializer;

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;

    public JedisClientCluster(JedisCluster jedisPool,IKeyNamingPolicy keyNamingPolicy,SerializerUtil serializer){
        this.jedisPool = jedisPool;
        this.keyNamingPolicy = keyNamingPolicy;
        this.serializer = serializer;
    }

    // 给某个key设值
    public void set(Object key, Object value) {
        byte[] keyBytes = serializer.serializeKey(keyNamingPolicy.getKeyName(key));
        byte[] valueBytes = serializer.serializeValue(value);
        jedisPool.set(keyBytes, valueBytes);
    }

    // 给某个key设值
    public void set(Object key, Object value, int expireTime) {
        byte[] keyBytes = serializer.serializeKey(keyNamingPolicy.getKeyName(key));
        byte[] valueBytes = serializer.serializeValue(value);
        jedisPool.setex(keyBytes, expireTime, valueBytes);
    }

    // 根据key获取value
    public Object get(Object key) {
        byte[] keyBytes = serializer.serializeKey(keyNamingPolicy.getKeyName(key));
        byte[] valueBytes = jedisPool.get(keyBytes);
        return serializer.deserializeValue(valueBytes);
    }

    // 根据键值获取value
    public Object hashGet(Object key, String field) {
        byte[] keyBytes = serializer.serializeKey(keyNamingPolicy.getKeyName(key));
        byte[] fieldBytes = serializer.serializeKey(field);
        byte[] valueBytes = jedisPool.hget(keyBytes, fieldBytes);
        return serializer.deserializeValue(valueBytes);

    }

    public void hashSet(Object key, String field, Object value) {
        byte[] keyBytes = serializer.serializeKey(keyNamingPolicy.getKeyName(key));
        byte[] fieldBytes = serializer.serializeKey(field);
        byte[] valueBytes = serializer.serializeValue(value);
        jedisPool.hset(keyBytes, fieldBytes, valueBytes);
    }

    public Map<String, Object> hashAllGet(Object key) {
        byte[] keyBytes = serializer.serializeKey(keyNamingPolicy.getKeyName(key));
        Map<byte[], byte[]> map = jedisPool.hgetAll(keyBytes);
        Map<String, Object> valueMap = new HashMap<>();
        Set<Map.Entry<byte[], byte[]>> valueSet = map.entrySet();
        for (Map.Entry<byte[], byte[]> entry : valueSet) {
            valueMap.put(serializer.deserializeKey(entry.getKey()), serializer.deserializeValue(entry.getValue()));
        }
        return valueMap;

    }

    // 判断key是否存在
    public boolean existKey(Object key) {
        byte[] keyBytes = serializer.serializeKey(keyNamingPolicy.getKeyName(key));
        return jedisPool.exists(keyBytes);
    }

    // 删除
    public void delKey(Object key) {
        byte[] keyBytes = serializer.serializeKey(keyNamingPolicy.getKeyName(key));
        jedisPool.del(keyBytes);
    }

    /**
     * 加分布式锁
     *
     * @param lockKey
     * @param lockValue
     * @param expireTime
     * @return
     */
    public boolean tryGetDistributedLock(String lockKey, String lockValue, int expireTime) {
        boolean re = false;
        String result = jedisPool.set(lockKey, lockValue, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            re = true;
        }
        return re;
    }

    /**
     * 解分布式锁
     *
     * @param lockKey
     * @param lockValue
     * @return
     */
    public boolean releaseDistributedLock(String lockKey, String lockValue) {
        boolean re = false;
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedisPool.eval(script, Collections.singletonList(lockKey), Collections.singletonList(lockValue));

        if (RELEASE_SUCCESS.equals(result)) {
            re = true;
        }
        return re;
    }

}